package com.example.base_model.utils


import com.blankj.utilcode.util.LogUtils
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.coroutines.CoroutineContext


/**
 * @Author jiangKunKun
 * @CreateDate 2025/7/25
 * @Description 循环定时器，提供在指定协程作用域内周期性执行任务的能力，支持延迟、间隔、最大次数、暂停/恢复和停止等功能。
 * @SpittingGrooves
 */
class LoopTimer (
    private val coroutineScope: CoroutineScope, // <!----- 用于启动和管理定时器协程的 CoroutineScope。----->
    private val coroutineContext: CoroutineContext = Dispatchers.Main // <!----- 定时器协程运行的上下文，默认为主线程。----->
){
    /**
     * 初始延迟时间（毫秒）。
     * 定时器在首次执行任务前等待的时间。
     * 默认为 0L，即不延迟。
     */
    private var initialDelay: Long = 0L
    /**
     * 循环间隔时间（毫秒）。
     * 每次任务执行之间的时间间隔。
     * 默认为 1000L (1秒)。
     */
    private var interval: Long = 1000L
    /**
     * 最大循环次数。
     * -1 表示无限循环。
     * 任何正整数表示定时器将执行指定次数后停止。
     * 默认为 -1 (无限循环)。
     */
    private var maxCount: Int = -1

    /**
     * 当前定时器任务的 Job 对象。
     * 用于管理（取消）定时器协程的生命周期。
     * 如果定时器未启动或已停止，则为 null。
     */
    private var job: Job? = null
    /**
     * 原子布尔值，表示定时器是否处于暂停状态。
     * true 表示暂停，false 表示运行。
     * 使用 AtomicBoolean 确保线程安全。
     */
    private val isPaused = AtomicBoolean(false)
    /**
     * 原子布尔值，表示定时器是否已停止。
     * true 表示已停止，false 表示正在运行或暂停。
     * 使用 AtomicBoolean 确保线程安全。
     */
    private val isStopped = AtomicBoolean(false)

    /**
     * 每次循环执行时调用的回调函数。
     * 接受当前循环次数 (Int) 作为参数。
     * 如果不需要每次循环回调，则为 null。
     */
    private var onTick: ((Int) -> Unit)? = null
    /**
     * 循环完成时调用的回调函数。
     * 仅当 `maxCount` 不为 -1 (有限循环) 时有效。
     * 如果不需要完成回调，则为 null。
     */
    private var onComplete: (() -> Unit)? = null

    /**
     * 设置循环参数。
     * @param delay 初始延迟时间（毫秒），如果为 null 则不改变当前值。
     * @param interval 循环间隔时间（毫秒），如果为 null 则不改变当前值。
     * @param maxCount 最大循环次数（-1表示无限循环），如果为 null 则不改变当前值。
     * @return 当前 [LoopTimer] 实例，支持链式调用。
     */
    fun setParams(
        delay: Long? = null,
        interval: Long? = null,
        maxCount: Int? = null
    ): LoopTimer {
        delay?.let { this.initialDelay = it }
        interval?.let { this.interval = it }
        maxCount?.let { this.maxCount = it }
        return this
    }

    /**
     * 设置每次循环执行时的回调函数（可选）。
     * @param action 接收当前循环次数的 lambda 函数。
     * @return 当前 [LoopTimer] 实例，支持链式调用。
     */
    fun onTick(action: ((Int) -> Unit)?): LoopTimer {
        this.onTick = action
        return this
    }

    /**
     * 设置循环完成后的回调函数（可选）。
     * 仅当 [maxCount] 不为 -1 时有效。
     * @param action 循环完成时执行的 lambda 函数。
     * @return 当前 [LoopTimer] 实例，支持链式调用。
     */
    fun onComplete(action: (() -> Unit)?): LoopTimer {
        this.onComplete = action
        return this
    }

    /**
     * 开始循环定时器。
     * 如果定时器已在运行，会先停止旧的定时器再启动新的。
     * @return 当前 [LoopTimer] 实例，支持链式调用。
     */
    fun start(): LoopTimer {
        if (job?.isActive == true) {
            stop()
        }

        isStopped.set(false)
        isPaused.set(false)

        job = coroutineScope.launch(coroutineContext) {
            executeLoop()
        }

        return this
    }

    /**
     * 暂停循环定时器。
     * 定时器会停止执行 `onTick` 回调和 `delay`，但协程本身不会被取消。
     */
    fun pause() {
        isPaused.set(true)
    }

    /**
     * 恢复循环定时器。
     * 定时器将从暂停前的位置继续执行。
     */
    fun resume() {
        isPaused.set(false)
    }

    /**
     * 停止循环定时器。
     * 取消定时器任务的协程，并重置相关状态。
     */
    fun stop() {
        isStopped.set(true)
        job?.cancel()
        job = null
    }

    /**
     * 重置循环参数并重新开始定时器。
     * 会先停止当前定时器，然后设置新参数，最后重新启动。
     * @param initialDelay 初始延迟时间（毫秒），如果为 null 则不改变当前值。
     * @param interval 循环间隔时间（毫秒），如果为 null 则不改变当前值。
     * @param maxCount 最大循环次数（-1表示无限循环），如果为 null 则不改变当前值。
     * @return 当前 [LoopTimer] 实例，支持链式调用。
     */
    fun reset(
        initialDelay: Long? = null,
        interval: Long? = null,
        maxCount: Int? = null
    ): LoopTimer {
        stop()
        setParams(initialDelay, interval, maxCount)
        return start()
    }

    /**
     * 检查定时器是否正在运行。
     * 当 `job` 活跃且定时器未暂停、未停止时返回 true。
     */
    val isRunning: Boolean
        get() = job?.isActive == true && !isPaused.get() && !isStopped.get()

    /**
     * 检查定时器是否已暂停。
     * 当 `isPaused` 为 true 时返回 true。
     */
    val isTimerPaused: Boolean
        get() = isPaused.get()

    /**
     * 实际执行循环逻辑的挂起函数。
     * 处理初始延迟、循环次数、暂停逻辑、每次回调和完成回调。
     */
    private suspend fun executeLoop() {
        try {
            // 初始延迟
            if (initialDelay > 0) {
                delay(initialDelay)
            }

            var count = 0 // <!----- 循环计数器，记录当前已执行的循环次数。----->
            while (!isStopped.get() && (maxCount == -1 || count < maxCount)) {
                // 检查暂停状态
                while (isPaused.get() && !isStopped.get()) {
                    delay(50) // 短暂延迟以避免忙等待，释放 CPU
                }

                if (isStopped.get()) break // 如果在暂停期间被停止，则退出循环

                count++ // 先增加计数器

                // 执行回调 - 确保在主线程执行，因为 onTick 通常涉及UI操作
                onTick?.let { callback ->
                    withContext(Dispatchers.Main) {
                        callback(count)
                    }
                }

                // 检查是否完成（有限循环）
                if (maxCount != -1 && count >= maxCount) {
                    onComplete?.let { callback ->
                        withContext(Dispatchers.Main) {
                            callback()
                        }
                    }
                    break // 完成后退出循环
                }

                // 间隔延迟
                delay(interval)
            }
        } catch (e: CancellationException) {
            // 协程被取消，这是停止定时器的正常处理流程，无需额外操作
        } catch (e: Exception) {
            // 处理其他运行时异常
            LogUtils.d("LoopTimer", "An error occurred: ${e.message}")
        }
    }
}


/**
 * 创建 [LoopTimer] 的工厂方法。
 * 简化 [LoopTimer] 的创建过程，提供默认的 [CoroutineScope] 和 [CoroutineContext]。
 * @param coroutineScope 用于启动定时器协程的作用域，默认为 [GlobalScope]。
 * @param coroutineContext 定时器协程运行的上下文，默认为 [Dispatchers.Main]。
 * @return 一个新的 [LoopTimer] 实例。
 */
fun createLoopTimer(
    coroutineScope: CoroutineScope = GlobalScope,
    coroutineContext: CoroutineContext = Dispatchers.Main
): LoopTimer = LoopTimer(coroutineScope, coroutineContext)

/**
 * 为 [CoroutineScope] 扩展便捷方法，使其可以直接创建 [LoopTimer] 实例。
 * 定时器将使用此 [CoroutineScope] 作为其作用域。
 * @param coroutineContext 定时器协程运行的上下文，默认为 [Dispatchers.Main]。
 * @return 一个新的 [LoopTimer] 实例。
 */
fun CoroutineScope.loopTimer(
    coroutineContext: CoroutineContext = Dispatchers.Main
): LoopTimer = LoopTimer(this, coroutineContext)